<?php

class UsersController extends AppController {
	var $scaffold = 'admin';
	var $uses=array("User","Group");
	function beforeFilter() {
		$this->Auth->allowedActions=array('login','reg','state','logout','activate','initDB');
		parent::beforeFilter();

	}
	function require_login(){
		$this->set('user',array("success"=>0,"err"=>"Not Logged in.","errcode"=>1));
		$this->set('json',array("user"));
	}
	/*
	 * login() - login
	 *
	 * data:
	 *
	 * [POST] username
	 * [POST] password
	 *
	 * return:
	 *
	 * success: 1 if success. otherwise 0
	 * errmsg(optional): error message when fail.
	 * errcode(optional): error code.
	 *
	 */

	function login() {
		try{
			if ($this->Session->read('Auth.User')) {
				$this->set('user',array("success"=>1,"data"=>$this->Auth->user()));
				$this->set('json',array("user"));
				$this->render();
				return;
			}
			if(!$this->RequestHandler->isPost()){
				if($this->RequestHandler->isAjax()){
					throw new Exception("No form data.");
				}else{
					$this->helpers=array('Form', 'Html', 'Javascript', 'Time');
					$this->render(null,"default");
					return;
				}
			}
			if($this->params["form"]["username"]==null||$this->params["form"]["username"]==""){
				throw new Exception("No username.");
			}
			if($this->params["form"]["password"]==null||$this->params["form"]["password"]==""){
				throw new Exception("No password.");
			}
			$this->Auth->userScope = array('User.activated <>' => 0,'User.banned <>' => 1);
			if(!$data=$this->Auth->login(array("username"=>$this->params["form"]["username"],"password"=>$this->Auth->password($this->params["form"]["password"])),false)){
				throw new Exception("login failed.");
			}
			$this->User->update_ip($this->Session->read('Auth.User.id'),$this->_get_real_ip());
			$this->set('user',array("success"=>1,"data"=>$this->Auth->user()));
			$this->set('json',array("user"));
		}catch(Exception $exception){
			$this->set('user',array("success"=>0,"errmsg"=>$exception->getMessage()));
			$this->set('json',array("user"));
		}
	}

	/*
	 * state() - show the status of user
	 *
	 * data:
	 *
	 * Null
	 *
	 * return:
	 *
	 * user: user's data. Null if not logged in.
	 *
	 */
	function state(){
		$this->set('user',$this->Auth->user());
		$this->set('json',array("user"));
	}

	/*
	 * logout() - logout
	 *
	 * data:
	 *
	 * Null
	 *
	 * return:
	 *
	 * success: 1 if success. otherwise 0
	 * errmsg(optional): error message when fail.
	 * errcode(optional): error code.
	 *
	 */

	function logout() {
		$this->Auth->logout();
		$this->set('user',array("success"=>1));
		$this->set('json',array("user"));
	}

	/*
	 * reg() - registration
	 *
	 * data:
	 * [POST] username
	 * [POST] realname
	 * [POST] password
	 * [POST] password_confirm
	 * [POST] student_id
	 * [POST] nickname
	 * [POST] email
	 *
	 * return:
	 *
	 * success: 1 if success. 0 otherwise.
	 * errmsg(optional): error message when fail.
	 * errcode(optional): error code.
	 */

	function reg(){
		try{
			if ($this->Session->read('Auth.User')) {
				throw new Exception("Already logged in.");
			}
			if(!($this->RequestHandler->isPost())){
				if($this->RequestHandler->isAjax()){
					throw new Exception("No form data.");
				}else{
					$this->helpers=array('Form', 'Html', 'Javascript', 'Time');
					$this->render(null,"launcher");
					return;
				}
			}
			if($this->params["form"]["password"]==null||$this->params["form"]["password"]==""){
				throw new Exception("No password.");
			}
			if($this->params["form"]["password_confirm"]==null||$this->params["form"]["password_confirm"]==""){
				throw new Exception("No password_confirm.");
			}
			if($this->params["form"]["password"]!=$this->params["form"]["password_confirm"]){
				throw new Exception("Wrong password");
			}
			$act_code=sha1($this->_get_real_ip().$this->params["form"]["username"].time().rand());
			$this->User->set(array(
				"User"=>array(
					"username"=>$this->params["form"]["username"],
					"realname"=>$this->params["form"]["realname"],
					"password"=>$this->Auth->password($this->params["form"]["password"]),
					"student_id"=>$this->params["form"]["student_id"],
					"nickname"=>$this->params["form"]["nickname"],
					"email"=>$this->params["form"]["email"],
					"group_id"=>1,
					"activated"=>1,
					"reg_ip"=>$this->_get_real_ip(),
					"act_code"=>$act_code
			)));
			if(!$this->User->validates()){
				$this->set('user',array("success"=>0,"errmsg"=>"Wrong Data Format","error"=>$this->User->invalidFields()));
				$this->set('json',array("user"));
				$this->render();
				return;
			}
			$save=$this->User->save();
			if(!$save){
				throw new Exception("Save failed.");
			}
			$this->Auth->logout();
			if(!$this->Auth->login(array("username"=>$this->params["form"]["username"],"password"=>$this->Auth->password($this->params["form"]["password"])),false)){
				throw new Exception("re-login failed.");
			}
			$this->User->update_ip($this->Session->read('Auth.User.id'),$this->_get_real_ip());
			$this->set('user',array("success"=>1));
			$this->set('json',array("user"));
		}catch(Exception $exception){
			$this->set('user',array("success"=>0,"errmsg"=>$exception->getMessage()));
			$this->set('json',array("user"));
		}
	}
	/*
	 *
	 * listuser() - return user list.
	 *
	 * data:
	 *
	 * Null
	 *
	 * return:
	 *
	 * users[]: json object of user data.
	 * success: 1 if success. 0 otherwise.
	 * errmsg(optional): error message when fail.
	 * errcode(optional): error code.
	 *
	 */

	function listuser(){
		$this->set('user',$this->User->find("all"));
		$this->set('json',array("user"));
	}

	/*
	 *
	 * update() - updates user profile.
	 *
	 * [POST] username
	 * [POST] realname
	 * [POST] password
	 * [POST] password_confirm
	 * [POST] student_id
	 * [POST] nickname
	 * [POST] email
	 *
	 * return:
	 *
	 * success: 1 if success. 0 otherwise.
	 * errmsg(optional): error message when fail.
	 * errcode(optional): error code.
	 *
	 * */
	function update(){
		try{
			if (!$this->Session->read('Auth.User')) {
				throw new Exception("Not logged in.");
			}
			if(!($this->RequestHandler->isPost())){
				if($this->RequestHandler->isAjax()){
					throw new Exception("No form data.");
				}else{
					$this->helpers=array('Form', 'Html', 'Javascript', 'Time');
					$this->render(null,"launcher");
					return;
				}
			}
			$this->User->set(array(
				"User"=>array(
					"id"=>$this->Session->read("Auth.User.id"),
					"realname"=>$this->params["form"]["realname"],
					"student_id"=>$this->params["form"]["student_id"],
					"nickname"=>$this->params["form"]["nickname"],
					"email"=>$this->params["form"]["email"],
			)));
			if($this->params["form"]["old_password"]){
				$this->params["form"]["change_password"]=true;
			}else{
				$this->params["form"]["change_password"]=false;
			}
			if($this->params["form"]["change_password"]){
				if($this->params["form"]["password"]==null||$this->params["form"]["password"]==""){
					throw new Exception("No password.");
				}
				if($this->params["form"]["password_confirm"]==null||$this->params["form"]["password_confirm"]==""){
					throw new Exception("No password_confirm.");
				}
				if($this->params["form"]["password"]!=$this->params["form"]["password_confirm"]){
					throw new Exception("Wrong password");
				}
				if($this->params["form"]["password"]!=$this->params["form"]["password_confirm"]){
					throw new Exception("Wrong password");
				}
				if($this->Auth->password($this->params["form"]["old_password"])!=$this->Session->read("Auth.User.password")){
					throw new Exception("Wrong old password");
				}
				$this->User->set("password",$this->Auth->password($this->params["form"]["password"]));
			}
			if(!$this->User->validates()){
				$this->set('user',array("success"=>0,"errmsg"=>"Wrong Data Format","error"=>$this->User->invalidFields()));
				$this->set('json',array("user"));
				$this->render();
				return;
			}
			$save=$this->User->save();
			if(!$save){
				throw new Exception("Save failed.");
			}
			$this->set('user',array("success"=>1));
			$this->set('json',array("user"));
		}catch(Exception $exception){
			$this->set('user',array("success"=>0,"errmsg"=>$exception->getMessage()));
			$this->set('json',array("user"));
		}
	}



	/*
	 *
	 * activate() - activates user.
	 *
	 * [GET] id
	 * [GET] code
	 *
	 * return:
	 *
	 * success: 1 if success. 0 otherwise.
	 * errmsg(optional): error message when fail.
	 * errcode(optional): error code.
	 *
	 * */

	function activate($id,$code){
		try{
			$this->User->activate($id,$code);
			$this->set('user',array("success"=>1));
			$this->set('json',array("user"));
		}catch(Exception $exception){
			$this->set('user',array("success"=>0,"errmsg"=>$exception->getMessage()));
			$this->set('json',array("user"));
		}
	}

	// Access Init

	function initDB() {

		$this->User->query("TRUNCATE TABLE `cake_acos`");
		if (!Configure::read('debug')) {
			return $this->_stop();
		}
		$log = array();

		$aco =& $this->Acl->Aco;
		$root = $aco->node('controllers');
		if (!$root) {
			$aco->create(array('parent_id' => null, 'model' => null, 'alias' => 'controllers'));
			$root = $aco->save();
			$root['Aco']['id'] = $aco->id;
			$log[] = 'Created Aco node for controllers';
		} else {
			$root = $root[0];
		}

		App::import('Core', 'File');
		$Controllers = Configure::listObjects('controller');
		$appIndex = array_search('App', $Controllers);
		if ($appIndex !== false ) {
			unset($Controllers[$appIndex]);
		}
		$baseMethods = get_class_methods('Controller');
		$baseMethods[] = 'buildAcl';

		$Plugins = $this->_getPluginControllerNames();
		$Controllers = array_merge($Controllers, $Plugins);

		// look at each controller in app/controllers
		foreach ($Controllers as $ctrlName) {
			$methods = $this->_getClassMethods($this->_getPluginControllerPath($ctrlName));

			// Do all Plugins First
			if ($this->_isPlugin($ctrlName)){
				$pluginNode = $aco->node('controllers/'.$this->_getPluginName($ctrlName));
				if (!$pluginNode) {
					$aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginName($ctrlName)));
					$pluginNode = $aco->save();
					$pluginNode['Aco']['id'] = $aco->id;
					$log[] = 'Created Aco node for ' . $this->_getPluginName($ctrlName) . ' Plugin';
				}
			}
			// find / make controller node
			$controllerNode = $aco->node('controllers/'.$ctrlName);
			if (!$controllerNode) {
				if ($this->_isPlugin($ctrlName)){
					$pluginNode = $aco->node('controllers/' . $this->_getPluginName($ctrlName));
					$aco->create(array('parent_id' => $pluginNode['0']['Aco']['id'], 'model' => null, 'alias' => $this->_getPluginControllerName($ctrlName)));
					$controllerNode = $aco->save();
					$controllerNode['Aco']['id'] = $aco->id;
					$log[] = 'Created Aco node for ' . $this->_getPluginControllerName($ctrlName) . ' ' . $this->_getPluginName($ctrlName) . ' Plugin Controller';
				} else {
					$aco->create(array('parent_id' => $root['Aco']['id'], 'model' => null, 'alias' => $ctrlName));
					$controllerNode = $aco->save();
					$controllerNode['Aco']['id'] = $aco->id;
					$log[] = 'Created Aco node for ' . $ctrlName;
				}
			} else {
				$controllerNode = $controllerNode[0];
			}
			//clean the methods. to remove those in Controller and private actions.
			$methods=array_merge($methods,array("admin_index","admin_add","admin_edit","admin_delete","admin_view"));
			foreach ($methods as $k => $method) {
				if (strpos($method, '_', 0) === 0) {
					unset($methods[$k]);
					continue;
				}
				if (in_array($method, $baseMethods)) {
					unset($methods[$k]);
					continue;
				}
				$methodNode = $aco->node('controllers/'.$ctrlName.'/'.$method);
				if (!$methodNode) {
					$aco->create(array('parent_id' => $controllerNode['Aco']['id'], 'model' => null, 'alias' => $method));
					$methodNode = $aco->save();
					$log[] = 'Created Aco node for '. $method;
				}
			}
		}

		$this->User->query("TRUNCATE TABLE `cake_aros_acos`");
		$this->User->query("TRUNCATE TABLE `cake_aros`");
		// Get all of the groups
		$groups = $this->Group->find('all');
		// Loop through them ...
		foreach($groups as $group) {
			$aro = array();
			$aro['parent_id'] = null;
			$aro['foreign_key'] = $group["Group"]["id"];
			$aro['model'] = "Group";
			$this->Acl->Aro->create();
			$this->Acl->Aro->save($aro);
			$log[] = 'Created Aro node for '. $group["Group"]["name"];
		}
		// Get all of the Users
		$users = $this->User->find('all');
		foreach($users as $user) {
			$this->User->id=$user["User"]["id"];
			$parent = $this->User->node($this->User->parentNode());
			$aro = array();//$node[0];
			$aro['parent_id'] = $parent[0]['Aro']['id'];
			$aro['foreign_key'] = $user["User"]["id"];
			$aro['model'] = "User";
			$this->Acl->Aro->create();
			$this->Acl->Aro->save($aro);
			$log[] = 'Created Aro node for '. $user["User"]["username"];
		}
		$group =& $this->User->Group;
		//Allow admins to everything
		$group->id = 2;
		$this->Acl->allow($group, 'controllers');

		//allow managers to posts and widgets
		$group->id = 1;
		$this->Acl->deny($group, 'controllers');
		$this->Acl->deny($group, 'controllers/Users');
		$this->Acl->allow($group, 'controllers/Users/logout');
		$this->Acl->allow($group, 'controllers/Users/update');
		$this->Acl->deny($group, 'controllers/Problems');
		$this->Acl->allow($group, 'controllers/Problems/answer');
		$this->Acl->allow($group, 'controllers/Problems/get');
		$this->Acl->allow($group, 'controllers/Problems/index');
		$this->Acl->deny($group, 'controllers/Scoreboards');
		$this->Acl->allow($group, 'controllers/Scoreboards/index');
		$this->Acl->allow($group, 'controllers/Scoreboards/user_scoreboard');
		$this->Acl->allow($group, 'controllers/Scoreboards/question_scoreboard');
		$this->Acl->deny($group, 'controllers/Launcher');
		$this->Acl->allow($group, 'controllers/Launcher/index');
		$this->set('user',array("success"=>1));
		$this->set('json',array("user"));

		if(count($log)>0) {
			debug($log);
		}
	}

	function _getClassMethods($ctrlName = null) {
		App::import('Controller', $ctrlName);
		if (strlen(strstr($ctrlName, '.')) > 0) {
			// plugin's controller
			$num = strpos($ctrlName, '.');
			$ctrlName = substr($ctrlName, $num+1);
		}
		$ctrlclass = $ctrlName . 'Controller';
		return get_class_methods($ctrlclass);
	}

	function _isPlugin($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) > 1) {
			return true;
		} else {
			return false;
		}
	}

	function _getPluginControllerPath($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) == 2) {
			return $arr[0] . '.' . $arr[1];
		} else {
			return $arr[0];
		}
	}

	function _getPluginName($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) == 2) {
			return $arr[0];
		} else {
			return false;
		}
	}

	function _getPluginControllerName($ctrlName = null) {
		$arr = String::tokenize($ctrlName, '/');
		if (count($arr) == 2) {
			return $arr[1];
		} else {
			return false;
		}
	}

	/**
	 * Get the names of the plugin controllers ...
	 *
	 * This function will get an array of the plugin controller names, and
	 * also makes sure the controllers are available for us to get the
	 * method names by doing an App::import for each plugin controller.
	 *
	 * @return array of plugin names.
	 *
	 */
	function _getPluginControllerNames() {
		App::import('Core', 'File', 'Folder');
		$paths = Configure::getInstance();
		$folder =& new Folder();
		$folder->cd(APP . 'plugins');

		// Get the list of plugins
		$Plugins = $folder->read();
		$Plugins = $Plugins[0];
		$arr = array();

		// Loop through the plugins
		foreach($Plugins as $pluginName) {
			// Change directory to the plugin
			$didCD = $folder->cd(APP . 'plugins'. DS . $pluginName . DS . 'controllers');
			// Get a list of the files that have a file name that ends
			// with controller.php
			$files = $folder->findRecursive('.*_controller\.php');

			// Loop through the controllers we found in the plugins directory
			foreach($files as $fileName) {
				// Get the base file name
				$file = basename($fileName);

				// Get the controller name
				$file = Inflector::camelize(substr($file, 0, strlen($file)-strlen('_controller.php')));
				if (!preg_match('/^'. Inflector::humanize($pluginName). 'App/', $file)) {
					if (!App::import('Controller', $pluginName.'.'.$file)) {
						debug('Error importing '.$file.' for plugin '.$pluginName);
					} else {
						/// Now prepend the Plugin name ...
						// This is required to allow us to fetch the method names.
						$arr[] = Inflector::humanize($pluginName) . "/" . $file;
					}
				}
			}
		}
		return $arr;
	}
};

?>
